/*
 *  Copyright 2011 yura.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package org.opu.pc.domain.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.opu.pc.domain.dao.AbstractDao;
import org.opu.pc.domain.domains.AbstractDomain;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

/**
 *
 * @author yura
 */
public abstract class AbstractHibernateDao 
<KeyType extends Serializable, T extends AbstractDomain<KeyType>>
/*<T extends Serializable, KeyType extends Serializable>*/
implements AbstractDao<KeyType, T> {

    /**
     * Method to return the class of the domain object
     */
    protected abstract Class<T> getDomainClass();
    protected HibernateTemplate hibernateTemplate;

    public void setSessionFactory(SessionFactory sf) {
    	hibernateTemplate = new HibernateTemplate(sf);
    }

    @Override
	public T load(KeyType id) {
        return (T) hibernateTemplate.load(getDomainClass(), id);
    }

    @Override
	public T get(KeyType id) {
        return (T) hibernateTemplate.get(getDomainClass(), id);
    }

    @SuppressWarnings("unchecked")
    public List<T> getList(final int startIndex, final int maxResult) {
        List<T> results = null;
        if (startIndex > -1 && maxResult > -1) {

            results = hibernateTemplate.execute(new HibernateCallback<List<T>>() {

                @Override
                public List<T> doInHibernate(Session session)
                        throws HibernateException, SQLException {
                    Criteria crit = session.createCriteria(getDomainClass());
                    crit.setFirstResult(startIndex).setMaxResults(maxResult);
                    return crit.list();
                }
            });
        } else {
            return getList();
        }
        return new ArrayList<T>(new HashSet<T>(results));
    }

    @Override
	@SuppressWarnings("unchecked")
    public List<T> getList() {
        List<T> results = null;
        results = hibernateTemplate.execute(new HibernateCallback<List<T>>() {

            @Override
            public List<T> doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria crit = session.createCriteria(getDomainClass());
                return crit.list();
            }
        });

        return new ArrayList<T>(new HashSet<T>(results));
    }

	@SuppressWarnings("unchecked")
	public KeyType save(final T object) {
        KeyType save = (KeyType) hibernateTemplate.save(object);
        object.setId(save);
        flush();
        return save;
    }

	@Override
	public void saveOrUpdate(T object) {
        hibernateTemplate.saveOrUpdate(object);
        flush();
    }

	@Override
	public void delete(T object) {
        hibernateTemplate.delete(object);
        flush();
    }

    public void deleteAll(Collection<T> objects) {
        hibernateTemplate.deleteAll(objects);
        flush();
    }

    protected void flush() throws DataAccessException {
        hibernateTemplate.flush();
        hibernateTemplate.clear();
    }
}
